package com.ehotting.edsta.circuitDesign.handler;

import com.ehotting.edsta.circuitDesign.enums.BaseEnum;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

/**
 * 使用BaseEnum 指定枚举会映射的数据
 * @param <E> BaseEnum
 * 处理枚举映射
 */
@MappedTypes(BaseEnum.class)
public class EnumTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {

    /** 枚举类型 */
    private final Class<E> type;

    /** 使用 map 类型代替 EnumOrdinalTypeHandler 中 E[] enums 枚举数组， 解决 enum key 未从0开始的问题 */
    private final Map<Integer, E> enumMap = new HashMap<>();

    public EnumTypeHandler(Class<E> type) {
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        }

        // 初始化枚举类型
        this.type = type;
        // 按顺序获取枚举类型
        E[] enums = type.getEnumConstants();
        if (enums == null) {
            throw new IllegalArgumentException(
                    type.getSimpleName() + " does not represent an enum type.");
        }
        // 遍历枚举类型
        for (E e : enums) {
            // 将枚举转换为 EnumIntegerKeyInterface 类型，调用其 getEnumIntegerKey 方法获取枚举 key 作为 enumMap的 key
            BaseEnum enumIntegerKeyInterface = (BaseEnum) e;
            this.enumMap.put(enumIntegerKeyInterface.getValue(), e);
        }
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType)
            throws SQLException {
        // 将枚举转换为 BaseEnum 类型 并设置参数
        BaseEnum enumIntegerKeyInterface = (BaseEnum) parameter;
        ps.setInt(i, enumIntegerKeyInterface.getValue());
    }

    @Override
    public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
        int key = rs.getInt(columnName);
        if (key == 0 && rs.wasNull()) {
            return null;
        }
        return getIntegerEnum(key);
    }

    @Override
    public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        int key = rs.getInt(columnIndex);
        if (key == 0 && rs.wasNull()) {
            return null;
        }
        return getIntegerEnum(key);
    }

    @Override
    public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        int key = cs.getInt(columnIndex);
        if (key == 0 && cs.wasNull()) {
            return null;
        }
        return getIntegerEnum(key);
    }

    /**
     * @param key 数据库值 对应的枚举 key
     * @return 对应的枚举类型
     */
    private E getIntegerEnum(int key) {
        try {
            return this.enumMap.get(key);
        } catch (Exception ex) {
            throw new IllegalArgumentException(
                    "Cannot convertElement " + key + " to " + type.getSimpleName() + " by value.", ex);
        }
    }


}
